package com.koron.css2.workflow;

import com.koron.css2.ServerInterface;
import com.koron.css2.baseConfig.bean.PubReceiptBean;
import com.koron.css2.baseConfig.mapper.PubReceiptMapper;
import com.koron.css2.serviceManage.bean.RequestBean;
import com.koron.css2.serviceManage.bean.UserInfoBean;
import com.koron.css2.serviceManage.utils.JsonUtils;
import com.koron.css2.workflow.bean.NextTaskNodeInfoBean;
import com.koron.css2.workflow.bean.NodeInfoBean;
import com.koron.css2.workflow.bean.ProcessCommitBean;
import com.koron.css2.workflow.bean.ProcessStartBean;
import com.koron.css2.workflow.variables.WorkflowVariable;
import com.koron.util.Constant;
import com.koron.util.DBSourceUtils;
import com.koron.util.SpringContextHolder;
import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.lang3.StringUtils;
import org.koron.ebs.mybatis.SessionFactory;
import org.swan.bean.MessageBean;

import java.util.*;
import java.util.stream.Collectors;

/**
 * 将通用的流程审批功能封装起来
 * 如果有特殊的审批动作只需要继承这个类进行扩展即可
 * @author admin
 * @version 2.1
 * @since today
 *
 */
public abstract class  AbstractProcessCommit implements ServerInterface{
	
	protected static final Map<String, ProcessInterface> INTERFACE_MAP = new HashMap<>();
	
	protected Map<String, WorkflowVariable> workflowVariables = SpringContextHolder.getBeansOfType(WorkflowVariable.class);
	
	/**
	 * 流程提交之前需要做的操作
	 * @param factory
	 * @param userInfo 当前操作的用户信息
	 * @param param
	 * @return
	 */
	public MessageBean<?> before(SessionFactory factory, UserInfoBean userInfo, Map<String, String> param){
		MessageBean<Void> info = MessageBean.create(Constant.MESSAGE_INT_SUCCESS, "success", Void.class);
		String receiptType = param.get("receiptType");
		if(StringUtils.isEmpty(receiptType)) {
			info.setCode(Constant.MESSAGE_INT_FAIL);
			info.setDescription("单据类型不能为空");
			return info;
		}
		return info;
	};
	
	/**
	 * 
	 * @param factory
	 * @param userInfo
	 * @param param
	 * @return
	 */
	public void after(SessionFactory factory, UserInfoBean userInfo, Map<String, String> param, NextTaskNodeInfoBean nextTaskInfo){
		
	};
	
	@Override
	public MessageBean<?> exec(SessionFactory factory, UserInfoBean userInfo, RequestBean req) {
		MessageBean<?> info = MessageBean.create(Constant.MESSAGE_INT_SUCCESS, "success", Void.class);
		try {
			Map<String, String> map = JsonUtils.objectToPojo(req.getData(), Map.class);
			ProcessCommitBean pcBean = JsonUtils.objectToPojo(req.getData(), ProcessCommitBean.class);
			PubReceiptMapper mapper = factory.getMapper(PubReceiptMapper.class,DBSourceUtils.getDbEnv(userInfo.getCurWaterCode()));
			PubReceiptMapper pubmapper = factory.getMapper(PubReceiptMapper.class);
			info = before(factory, userInfo, map);
			if(Constant.MESSAGE_INT_SUCCESS != info.getCode()) {
				return info;
			}
			String receiptType = map.get("receiptType");
			pcBean.setOperator(userInfo.getUserInfo().getCode());
			pcBean.setSetCode(pubmapper.getWorkflowApp(userInfo.getCurWaterCode()));
			PubReceiptBean receipt = pubmapper.selectPubReceipt(receiptType);
			Objects.requireNonNull(receipt, "未找到单据信息");
			pcBean.setProcessCode(receipt.getProcessCode());
			if(receiptType.indexOf("#") != -1) {
				receiptType = receiptType.substring(0, receiptType.lastIndexOf("#"));
			}
			ProcessInterface processInterface = null;
			String processInstanceId = "";
			String nowCode = "";
			String nextCode = "";
			String nextCodeName = "";
			String nextCandidateUsers = ""; //下一节点办理人
			Map<String,String> billMap = mapper.getBillWorkflowInfo(receiptType, pcBean.getBillId());
			Objects.requireNonNull(billMap, "请先保存单据");
			processInstanceId = billMap.get("processInstanceId");
			nowCode = StringUtils.defaultIfEmpty(billMap.get("processState"), "START");
			if(StringUtils.isNotBlank(receipt.getWorkflowInterface())) {
				processInterface = INTERFACE_MAP.get(receipt.getWorkflowInterface());
				if(processInterface == null) {
					processInterface = (ProcessInterface) Class.forName(receipt.getWorkflowInterface()).newInstance();
					INTERFACE_MAP.put(receipt.getWorkflowInterface(), processInterface);
				}
				MessageBean<?> runRet = processInterface.before(factory, userInfo, pcBean.getBillId(), nowCode, pcBean.getOperation());
				if(runRet != null && runRet.getCode() != Constant.MESSAGE_INT_SUCCESS) {
					throw new RuntimeException(runRet.getDescription());
				}
			}
			if(workflowVariables.get(receiptType.toLowerCase()) != null) {
				Map<String, Object> varialbes = workflowVariables.get(receiptType.toLowerCase()).getVariable(factory, pcBean.getFormVariables(), pcBean.getBillId(), userInfo);
				pcBean.setFormVariables(varialbes);
			}else {
				if(pcBean.getFormVariables() == null) {
					pcBean.setFormVariables(new HashMap<String, Object>());
				}
			}
			NextTaskNodeInfoBean nextTaskNodeInfo = null;
			if(StringUtils.isBlank(processInstanceId)) {
				ProcessStartBean psBean = new ProcessStartBean();
				BeanUtils.copyProperties(psBean, pcBean);
				if (Objects.equals("pj_info_new", receiptType)){
					psBean.setTitle(billMap.get("install_addr"));
				}else {
					psBean.setTitle("单据编号：" + billMap.get("billNo"));
				}
				psBean.setBillNo(billMap.get("billNo"));
				nextTaskNodeInfo = WorkflowImpl.startProcessInstance(psBean);
				processInstanceId = nextTaskNodeInfo.getProcessInstanceId();
				List<NodeInfoBean> nodeInfo = nextTaskNodeInfo.getCurNodes();
				if(nodeInfo != null) {
					nowCode = "START";
					Set<String> nextCodeSet = nodeInfo.stream().map(t -> t.getCode()).collect(Collectors.toSet());
					Set<String> nextCodeNameSet = nodeInfo.stream().map(t -> t.getName()).collect(Collectors.toSet());
					nextCode = nextCodeSet.stream().collect(Collectors.joining(","));
					nextCodeName = nextCodeNameSet.stream().collect(Collectors.joining(","));
					nextCandidateUsers = nextTaskNodeInfo.getCandidatesName();
				}
			} else {
				nextTaskNodeInfo = WorkflowImpl.workflowsubmit(pcBean);
				List<NodeInfoBean> nodeInfo = nextTaskNodeInfo.getCurNodes();
				nowCode = nextTaskNodeInfo.getPreNodeCode();
				Set<String> nextCodeSet = nodeInfo.stream().map(t -> t.getCode()).collect(Collectors.toSet());
				Set<String> nextCodeNameSet = nodeInfo.stream().map(t -> t.getName()).collect(Collectors.toSet());
				nextCode = nextCodeSet.stream().collect(Collectors.joining(","));
				nextCodeName = nextCodeNameSet.stream().collect(Collectors.joining(","));
				nextCandidateUsers = nextTaskNodeInfo.getCandidatesName();
			}
			mapper.updateBillWorkflowInfo(receiptType, pcBean.getBillId(), processInstanceId, nextCode, nextCodeName, nextCandidateUsers);
			if(processInterface != null) {
				MessageBean<?> runRet = processInterface.after(factory, userInfo, pcBean.getBillId(), nowCode, nextCode);
				if(runRet != null && runRet.getCode() != Constant.MESSAGE_INT_SUCCESS) {
					throw new RuntimeException(runRet.getDescription());
				}
			}
			after(factory, userInfo, map, nextTaskNodeInfo);
		} catch (Exception e) {
			factory.close(false);
			info.setCode(Constant.MESSAGE_INT_FAIL);
			info.setDescription(e.getMessage());
			logger.error(e.getMessage(), e);
		}
		return info;
	}
}